package com.longrise.filedownloader;


import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;

import com.longrise.filedownloader.db.DBDAO;
import com.longrise.filedownloader.db.DownLoadStatusConstants;
import com.longrise.filedownloader.db.SqlDownloadBean;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


public class DownloadManager implements OnDownloadFinishListener {
    private static final String TAG = "DownloadManager111";

    private final Context mContext;

    private final int MAX_DOWNLOADING_TASK = 3; // 最大同时下载数

    private final String mUserId;

    private boolean isAbleDownload = true; //当前是否能下载

    private Map<String, DownLoader> mAllTaskList = new HashMap<>();
    //下载中列表
    private List<DownLoader> mDownloadingTaskList = new ArrayList<>();

    private static DownloadManager mDownloadManager = null;

    //等待下载的列表
    private List<DownLoader> mWaittingTaskList = new ArrayList<>();

    //暂停下载的列表
    private List<DownLoader> mPauseTaskList = new ArrayList<>();

    private ThreadPoolExecutor mThreadPoll; //线程池

    private DBDAO mDao;

    private final int START_TASK = 0;
    private static final int PAUSE_TASK = 1;
    private static final int ADDANDINIT_TASK = 3;
    /**
     * 服务器是否支持断点续传
     */
    private boolean isSupportBreakpoint = true;

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case START_TASK:
                    DownLoader downloader = (DownLoader) msg.obj;
                    startTask(downloader);
                    break;
                case PAUSE_TASK:
                    DownLoader pauseDownloader = (DownLoader) msg.obj;
                    pauseTask(pauseDownloader);
                    break;
                case ADDANDINIT_TASK:
                    SqlDownloadBean sqlDownloadBean = (SqlDownloadBean) msg.obj;
                    DownLoader downLoader = new DownLoader(mContext, mThreadPoll, sqlDownloadBean);
                    mAllTaskList.put(downLoader.getUrl(), downLoader);
                    pauseTask(downLoader);
                    break;
            }
        }
    };
    private OnFileDownloadSuccessListener mFileDownloadSuccessListener;


    public DownloadManager(Context context, String userId) {

        this.mContext = context;
        this.mUserId = userId;
        init();
    }

    private void init() {
        mThreadPoll = new ThreadPoolExecutor(MAX_DOWNLOADING_TASK, MAX_DOWNLOADING_TASK, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(50));
        recoverData();
    }

    /**
     * 从数据库中恢复数据
     */
    private void recoverData() {
        mDao = new DBDAO(mContext);
        ArrayList<SqlDownloadBean> allDownloadBeans = mDao.getAllDownloadBeans(mUserId);
        if (allDownloadBeans != null && allDownloadBeans.size() > 0) {
            for (int i = 0; i < allDownloadBeans.size(); i++) {
                SqlDownloadBean sqlDownloadBean = allDownloadBeans.get(i);
                sqlDownloadBean.setDownloadStatus(DownLoadStatusConstants.PAUSE);
                DownLoader downLoader = new DownLoader(mContext, mThreadPoll, sqlDownloadBean);
                DownloadStatus status = getStatus(downLoader.getUrl());
                //软件初始化时 等待中 正在下载 暂停的都改为暂停状态
                if (DownloadStatus.SUCCESS != status) {
                    pauseTask(downLoader);
                } else {
                    //如果本地文件不存在了就将其放入暂停list 点击可以重新下载
                    File file = new File(sqlDownloadBean.getFilePath());
                    if (!file.exists()) {
                        pauseTask(downLoader);
                    }
                }

                mAllTaskList.put(downLoader.getUrl(), downLoader);
            }
        }
    }

    /**
     * 开始下载任务
     *
     * @param downLoader
     */
    private void startTask(DownLoader downLoader) {
        if (mDownloadingTaskList.size() > 0) {
            waitTask(downLoader);
        } else {
            downLoader.start(this);
            mDownloadingTaskList.add(downLoader);
        }

    }

    /**
     * 等待下载
     *
     * @param downLoader
     */
    private void waitTask(DownLoader downLoader) {
        mWaittingTaskList.add(downLoader);
        downLoader.waitNotice();
    }

    /**
     * 暂停下载
     *
     * @param downLoader
     */
    private void pauseTask(DownLoader downLoader) {
        mPauseTaskList.add(downLoader);
        downLoader.stop();
    }


    /**
     * 保存downloadbean到数据库
     *
     * @param sqlDownloadBean
     */
    private boolean saveDownloadbean(SqlDownloadBean sqlDownloadBean) {
        if (mDao == null) {
            mDao = new DBDAO(mContext);
        }
        boolean b = mDao.saveNewDownloadBean(sqlDownloadBean);
        return b;
    }


    /**
     * 暂停当前下载的任务 然后开启新任务
     */
    private void stopTaskAndStartNew() {
        for (int i = 0; i < mDownloadingTaskList.size(); i++) {
            DownLoader downLoader = mDownloadingTaskList.get(i);
            downLoader.stop();
            mPauseTaskList.add(downLoader);
        }
        mDownloadingTaskList.clear(); //移除正在下载的任务
        if (mWaittingTaskList.size() > 0) {
            DownLoader downLoader = mWaittingTaskList.get(0);
            mWaittingTaskList.remove(0);
            Message message = handler.obtainMessage();
            message.what = START_TASK;
            message.obj = downLoader;
            handler.sendMessage(message);
        }
    }


    /**
     * 下载成功了 开启新任务
     */
    private void startNew() {
        mDownloadingTaskList.clear(); //移除正在下载的任务
        if (mWaittingTaskList.size() > 0) {
            DownLoader downLoader = mWaittingTaskList.get(0);
            mWaittingTaskList.remove(0);
            Message message = handler.obtainMessage();
            message.what = START_TASK;
            message.obj = downLoader;
            handler.sendMessage(message);
        }
    }


    /**
     * 删除的时候先暂停下载
     * 全部暂停的时候也要先把正在下载的暂停
     */
    private void stopBefore() {
        if (mDownloadingTaskList.size() > 0) {
            DownLoader downLoader = mDownloadingTaskList.get(0);
            downLoader.stop();
            mWaittingTaskList.add(0, downLoader);
            mDownloadingTaskList.clear();
        }
    }


    /**
     * 删除单个任务
     *
     * @param
     */
    public boolean deleteTask(String url) {
        boolean deleteResult = false;
        if (mDao == null) {
            mDao = new DBDAO(mContext);
        }
        boolean deleteSuccess = mDao.deleteFile(mUserId, url);
        if (deleteSuccess) {
            DownLoader downLoader = mAllTaskList.get(url);
            if (downLoader != null) {
                downLoader.delete();
                if (mPauseTaskList.contains(downLoader)) {
                    mPauseTaskList.remove(downLoader);
                } else if (mWaittingTaskList.contains(downLoader)) {
                    mWaittingTaskList.remove(downLoader);
                } else if (mDownloadingTaskList.contains(downLoader)) {
                    stopTaskAndStartNew();
                }
                mAllTaskList.remove(downLoader);
                deleteResult = true;
            }

        }
        return deleteResult;
    }

    /**
     * 删除多个任务 更安全
     */
    public void deleteMultiTasks(List<String> urllist) {
        stopBefore();
        for (String url : urllist) {
            deleteTask(url);
        }
        startNew();
    }

    /**
     * 更改当前状态  下载 等待  等等
     *
     * @param url 如果url没在数据库中 则返回false
     */
    public boolean switchStatus(String url) {
        DownLoader downLoader = mAllTaskList.get(url);
        if (downLoader != null) {
            if (mDownloadingTaskList.contains(downLoader)) {
                //正在下载的,则将当前这个任务暂停,然后开启下一个等待中的任务
                stopTaskAndStartNew();
                return true;
            } else if (mWaittingTaskList.contains(downLoader)) {
                //等待中的任务,则将任务移到暂停列表
                pauseTask(downLoader);
                mWaittingTaskList.remove(downLoader);
                return true;

            } else if (mPauseTaskList.contains(downLoader)) {
                //暂停的任务,判断当前是否有任务在下载,如果有则等待,没有则开始下载
                if (mDownloadingTaskList.size() > 0) {
                    waitTask(downLoader);
                } else {
                    Message message = handler.obtainMessage();
                    message.what = START_TASK;
                    message.obj = downLoader;
                    handler.sendMessage(message);
                }
                mPauseTaskList.remove(downLoader);
                return true;
            } else {
                return false;
            }

        } else {
            //如果切换状态的时候没有这个url的话就添加下载
            //需要调用者处理 返回false调用addtask方法
            return false;
        }
    }


    /**
     * 添加下载任务
     *
     * @param url       网络请求网址
     * @param cachePath 本地缓存地址
     */
    public boolean addTask(String url, String cachePath) {
        return addTask(url, cachePath, null);

    }


    /**
     * 添加下载任务
     *
     * @param url       网络请求网址
     * @param cachePath 本地缓存地址
     * @param fileName  文件名
     * @return
     */
    public boolean addTask(String url, String cachePath, String fileName) {
        return addTask(url, cachePath, fileName, 0);
    }

    /**
     * 添加下载任务
     *
     * @param url       网络请求网址
     * @param cachePath 本地缓存地址
     * @param fileName  文件名
     * @param position  数据取出来后的排位
     * @return
     */
    public boolean addTask(String url, String cachePath, String fileName, int position) {
        boolean addresult = false;
        try {
            SqlDownloadBean sqlDownloadBean = new SqlDownloadBean();
            int index = cachePath.lastIndexOf("/");
            if (fileName == null) {
                fileName = cachePath.substring(index + 1, cachePath.length());
            }
            String tempFilePath = cachePath + ".tmp";
            sqlDownloadBean.setFileName(fileName);
            sqlDownloadBean.setFilePath(cachePath);
            sqlDownloadBean.setUrl(url);
            sqlDownloadBean.setDownloadSize(0);
            sqlDownloadBean.setFileSize(0);
            sqlDownloadBean.setTempFilePath(tempFilePath);
            sqlDownloadBean.setDownloadStatus(DownLoadStatusConstants.WAITTING);
            sqlDownloadBean.setUserId(mUserId);
            sqlDownloadBean.setPosition(position);
            boolean result = saveDownloadbean(sqlDownloadBean);
            if (result) {
                DownLoader downLoader = new DownLoader(mContext, mThreadPoll, sqlDownloadBean);
                mAllTaskList.put(downLoader.getUrl(), downLoader);
                if (mWaittingTaskList.size() > 0 || mDownloadingTaskList.size() > 0) {
                    waitTask(downLoader);
                } else {
                    Message message = handler.obtainMessage();
                    message.what = START_TASK;
                    message.obj = downLoader;
                    handler.sendMessage(message);
                }
                addresult = true;
            } else {
                addresult = false;
            }

        } catch (Exception e) {
            addresult = false;
        } finally {

            return addresult;
        }

    }

    /**
     * 如果有的url 数据库没有存 可以先调用此方法
     *
     * @param url       网络下载地址
     * @param cachePath 本地缓存地址
     */
    public void addAndInitTask(String url, String cachePath) {
        addAndInitTask(url, cachePath, null);
    }

    public void addAndInitTask(String url, String cachePath, String fileName) {
        addAndInitTask(url, cachePath, null, 0);
    }

    public void addAndInitTask(String url, String cachePath, String fileName, int position) {
        if (!mAllTaskList.containsKey(url)) {
            try {
                SqlDownloadBean sqlDownloadBean = new SqlDownloadBean();
                int index = cachePath.lastIndexOf("/");
                if (fileName == null) {
                    fileName = cachePath.substring(index + 1, cachePath.length());
                }
                String tempFilePath = cachePath + ".tmp";
                sqlDownloadBean.setFileName(fileName);
                sqlDownloadBean.setFilePath(cachePath);
                sqlDownloadBean.setUrl(url);
                sqlDownloadBean.setDownloadSize(0);
                sqlDownloadBean.setFileSize(0);
                sqlDownloadBean.setTempFilePath(tempFilePath);
                sqlDownloadBean.setDownloadStatus(DownLoadStatusConstants.WAITTING);
                sqlDownloadBean.setUserId(mUserId);
                sqlDownloadBean.setPosition(position);
                boolean result = saveDownloadbean(sqlDownloadBean);
                if (result) {
                    Message message = handler.obtainMessage();
                    message.what = ADDANDINIT_TASK;
                    message.obj = sqlDownloadBean;
                    handler.sendMessage(message);

                }
            } catch (Exception e) {
               e.printStackTrace();
            }
        }
    }

    /**
     * 将所给的地址的视频全部开始下载或者等待中
     *
     * @param urlList 视频下载地址
     */
    public void startAll(List<String> urlList) {
        for (String url : urlList) {
            DownLoader downLoader = mAllTaskList.get(url);
            if (downLoader != null) {
                if (mDownloadingTaskList.contains(downLoader)) {
                    //正在下载的item 不做处理
                } else if (mWaittingTaskList.contains(downLoader)) {
                    if (mDownloadingTaskList.size() > 0) {
                        //如果有下载中的item 则当前item 不做处理
                    } else {
                        Message message = handler.obtainMessage();
                        message.what = START_TASK;
                        message.obj = downLoader;
                        handler.sendMessage(message);
                        mWaittingTaskList.remove(downLoader);
                    }
                } else if (mPauseTaskList.contains(downLoader)) {
                    if (mDownloadingTaskList.size() > 0) {
                        waitTask(downLoader);
                    } else {
                        Message message = handler.obtainMessage();
                        message.what = START_TASK;
                        message.obj = downLoader;
                        handler.sendMessage(message);
                    }
                    mPauseTaskList.remove(downLoader);
                }
            }
        }
    }

    /**
     * 暂停下载
     *
     * @param urlList 需要暂停下载的url
     */
    public void stopAll(List<String> urlList) {
        stopBefore();
        for (String url : urlList) {
            DownLoader downLoader = mAllTaskList.get(url);
            if (downLoader != null) {
                if (mWaittingTaskList.contains(downLoader)) {
                    pauseTask(downLoader);
                    mWaittingTaskList.remove(downLoader);
                }
            }
        }
        startNew();
    }

    /**
     * 暂停当前用户的全部下载
     */
    public void stopAll() {
        stopBefore();
        Set<String> keySet = mAllTaskList.keySet();
        Iterator<String> it = keySet.iterator();
        while (it.hasNext()) {
            String key = it.next();
            DownLoader downLoader = mAllTaskList.get(key);
            if (mWaittingTaskList.contains(downLoader)) {
                pauseTask(downLoader);
                mWaittingTaskList.remove(downLoader);
            }
        }
    }

    /**
     * 是否已经添加到了任务
     *
     * @param url 网络地址
     */
    public boolean isHasAddedTask(String url) {
        if (mDao == null) {
            mDao = new DBDAO(mContext);
        }
        boolean addedTask = mDao.isHasAddedTask(url, mUserId);
        return addedTask;
    }

    /**
     * 是否已经添加到了任务
     *
     * @param url 下载地址
     * @return
     */
    public boolean isHasThisTask(String url) {
        if (mAllTaskList.containsKey(url)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取当前用户全部下载的地址
     *
     * @return
     */
    public ArrayList<String> getAllTaskUrl() {
        ArrayList<SqlDownloadBean> allDownloadBeans = mDao.getAllDownloadBeans(mUserId);
        ArrayList<String> allTaskUrl = new ArrayList<>();
        if (allDownloadBeans != null && allDownloadBeans.size() > 0) {
            for (int i = 0; i < allDownloadBeans.size(); i++) {
                SqlDownloadBean sqlDownloadBean = allDownloadBeans.get(i);
                String url = sqlDownloadBean.getUrl();
                allTaskUrl.add(url);
            }
        }
        return allTaskUrl;
    }


    /**
     * 获取文件名称
     *
     * @param url
     * @return
     */
    public String getFileName(String url) {
        if (mDao == null) {
            mDao = new DBDAO(mContext);
        }
        String fileName = mDao.getFileName(mUserId, url);

        return fileName;
    }

    /**
     * 获取文件的总大小
     *
     * @param url
     * @return
     */
    public long getFileSize(String url) {
        if (mDao == null) {
            mDao = new DBDAO(mContext);
        }
        long fileSize = mDao.getFileSize(mUserId, url);
        return fileSize;
    }

    /**
     * 获取文件已下载的大小
     *
     * @param url
     * @return
     */
    public long getFileDownloadedSize(String url) {
        if (mDao == null) {
            mDao = new DBDAO(mContext);
        }
        long fileDownloadedSize = mDao.getFileDownloadedSize(mUserId, url);
        return fileDownloadedSize;
    }

    /**
     * 获取文件已经下载的进度
     *
     * @param url
     * @return
     */
    public int getProgress(String url) {
        int progress = 0;
        long fileSize = getFileSize(url);
        long fileDownloadedSize = getFileDownloadedSize(url);
        if (fileSize == 0) {
            progress = 0;
        } else {
            progress = (int) (fileDownloadedSize * 100 / fileSize);
        }
        return progress;
    }

    /**
     * 判断缓存目录下面是否是原课件
     *
     * @return
     */
    public boolean isRealCourse(String cachePath, String url) {
        boolean result = false;
        File file = new File(cachePath);
        long actlength = file.length(); //本地视频的大小
        long fileSize = getFileSize(url);//视频下载是报错在数据库的视频的大小
        if (actlength >= fileSize) {
            result = true;
        }
        return result;
    }

    /**
     * 获取文件当前下载状态
     *
     * @param url
     * @return 0 获取状态失败
     * 1 正在下载
     * 2 暂停
     * 3 等待下载
     * 4 下载失败
     * 5 下载成功
     */
    public DownloadStatus getStatus(String url) {
        if (mDao == null) {
            mDao = new DBDAO(mContext);
        }
        int status = mDao.getFileStatus(mUserId, url);
        DownloadStatus downloadStatus = DownloadStatus.STOP;
        switch (status) {
            case 1:
                downloadStatus = DownloadStatus.DOWNLOADING;
                break;
            case 2:
                downloadStatus = DownloadStatus.STOP;
                break;
            case 3:
                downloadStatus = DownloadStatus.WAITTING;
                break;
            case 4:
                downloadStatus = DownloadStatus.FAIL;
                break;
            case 5:
                downloadStatus = DownloadStatus.SUCCESS;
                break;
        }
        return downloadStatus;
    }

    /**
     * 设置下载监听器
     *
     * @param url
     * @param listener
     */
    public void setOnFileDownloadStatusListener(String url, OnFileDownloadStatusListener listener) {
        DownLoader downLoader = mAllTaskList.get(url);
        if (downLoader != null) {
            downLoader.setOnFileDownloadStatusListener(listener);
        }
    }


    public void setOnFileDownloadSuccessListener(OnFileDownloadSuccessListener listener) {
        this.mFileDownloadSuccessListener = listener;
    }


    public void onDestory() {
        stopAll();
        mDownloadManager = null;
    }

    /**
     * 每一个downloader 下载完成调用接口
     *
     * @param downLoader
     */
    @Override
    public void onSuccess(DownLoader downLoader) {
        startNew();
        if (mFileDownloadSuccessListener != null) {
            mFileDownloadSuccessListener.onSuccess(downLoader.getUrl());
        }
    }

    /**
     * downloader 下载失败调用接口
     *
     * @param downLoader 下载失败后将downloader添加到暂停list
     */
    @Override
    public void onError(DownLoader downLoader) {
        startNew();
        mPauseTaskList.add(downLoader);
    }

    /**
     * 没有多余的内存空间了
     *
     * @param downLoader
     */
    @Override
    public void onNoFreeBufferSpace(DownLoader downLoader) {
        Toast.makeText(mContext, "您手机存储空间不足,无法下载", Toast.LENGTH_LONG).show();
        stopAll();
    }

    public enum DownloadStatus {
        DOWNLOADING, //下载中
        STOP,  //暂停中
        WAITTING, //等待中
        FAIL, //下载失败
        SUCCESS //下载成功
    }

}
